import React, { useCallback, useEffect, useRef } from "react";
import style from "./canvasGame.module.scss";
import createjs from "createjs-npm";
import lightBollImg from "./assets/img/flashing.png";
import meteorImg from "./assets/img/meteor-bg.png";
import star from "./assets/img/meteor-2.png";

let stage;
// let scoreCount = 0;
// 流星图片高宽
const [meteorImgHeight, meteorImgWidth] = [198, 234];
// 流星图片高宽比
const imgAspectRatio = meteorImgHeight / meteorImgWidth;
// 流星群数组
const meteorImgList = [];
// 星星群数组
const starImgList = [];
const CanvasGame = () => {
  const canvasContainerRef = useRef({});
  const canvasRef = useRef({});

  const resolveFunRepeat = useCallback(
    (func, times = 5) => Array.from({ length: times }, func),
    []
  );

  // 初始化canvas尺寸
  useEffect(() => {
    const { clientWidth, clientHeight } = canvasContainerRef.current;
    canvasRef.current.width = clientWidth;
    canvasRef.current.height = clientHeight;
  }, []);

  // tick事件
  const tickEvent = useCallback(() => {
    stage.update();
  }, []);

  // 初始化舞台
  const initStage = useCallback(() => {
    // 创建舞台
    stage = new createjs.Stage(style.canvas);

    //更新舞台将呈现下一帧
    createjs.Ticker.framerate = 60;
    createjs.Ticker.addEventListener("tick", tickEvent);
  }, [tickEvent]);

  // 创建单个闪烁星星方法
  const createLightBall = useCallback(() => {
    const lightBollBitmapImg = new createjs.Bitmap(lightBollImg);
    const { height, width } = stage.canvas;
    const assignObjData = {
      x: width * Math.random(),
      y: height * Math.random(),
      scale: 0.2,
    };

    // 对应属性合并到闪烁星星对象
    Object.assign(lightBollBitmapImg, assignObjData);

    // 星星闪烁
    createjs.Tween.get(lightBollBitmapImg, { loop: true })
      .wait(1000 * Math.random())
      .to({ alpha: 0 }, 1500);

    // 插入舞台
    stage.addChild(lightBollBitmapImg);
  }, []);

  // 创建单个固定初始位置的下落流星
  const createInitXOrYFallingMeteor = useCallback(() => {
    const meteorImgBitmapImg = new createjs.Bitmap(meteorImg);
    const { height, width } = stage.canvas;
    const randomValue = Math.random() > height / (height + width) ? 0 : 1;
    const randomValueToTypeArr = ["从上边缘进入", "从右边缘进入"];
    const scale = Math.abs(Math.random() - 0.5);
    let assignObjData = { scale };

    switch (randomValueToTypeArr[randomValue]) {
      case "从上边缘进入":
        Object.assign(assignObjData, {
          x:
            (width + meteorImgWidth * scale) * Math.random() -
            meteorImgWidth * scale,
          y: -meteorImgHeight * scale,
        });
        break;
      case "从右边缘进入":
        Object.assign(assignObjData, {
          x: width,
          y:
            (height + meteorImgHeight * scale) * Math.random() -
            meteorImgHeight * scale,
        });
        break;
      default:
        break;
    }

    Object.assign(meteorImgBitmapImg, assignObjData);

    createjs.Tween.get(meteorImgBitmapImg)
      .wait(1000 * Math.random())
      .to(
        {
          x: -meteorImgWidth * scale,
          y:
            assignObjData.y +
            imgAspectRatio * (assignObjData.x + meteorImgWidth * scale),
        },
        3000 * Math.random() + 3000
      );

    meteorImgList.push(meteorImgBitmapImg);
    // 插入舞台
    stage.addChild(meteorImgBitmapImg);
  }, []);

  // 创建单个随机位置下落流星
  const createFallingMeteor = useCallback(() => {
    const meteorImgBitmapImg = new createjs.Bitmap(meteorImg);
    const { height, width } = stage.canvas;
    const scale = Math.abs(Math.random() - 0.5);
    const assignObjData = {
      x: (width + meteorImgWidth * scale) * Math.random(),
      y:
        (height + meteorImgHeight * scale) * Math.random() -
        meteorImgHeight * scale,
      scale,
    };

    // 对应属性合并到流行对象
    Object.assign(meteorImgBitmapImg, assignObjData);

    // 星星闪烁
    createjs.Tween.get(meteorImgBitmapImg)
      .wait(1000 * Math.random())
      .to(
        {
          x: -meteorImgWidth * scale,
          y:
            assignObjData.y +
            imgAspectRatio *
              (assignObjData.x + meteorImgBitmapImg.image.width * scale),
        },
        10000 * Math.random()
      );

    meteorImgList.push(meteorImgBitmapImg);
    // 插入舞台
    stage.addChild(meteorImgBitmapImg);
  }, []);

  // 创建可点击的星星
  const createClickableStar = useCallback(() => {
    const starBitmapImg = new createjs.Bitmap(star);
    const { height, width } = stage.canvas;
    const randomValue = Math.random() > height / (height + width) ? 0 : 1;
    const randomValueToTypeArr = ["从上边缘进入", "从左边缘进入"];
    const scale = Math.abs(Math.random() - 0.5) + 0.15;
    // const rotation = 180 * Math.random();
    let assignObjData = { scale };

    switch (randomValueToTypeArr[randomValue]) {
      case "从上边缘进入":
        Object.assign(assignObjData, {
          x: width * Math.random(),
          y: -meteorImgHeight * scale,
        });
        break;
      case "从左边缘进入":
        Object.assign(assignObjData, {
          x: -meteorImgWidth * scale,
          y:
            (height + meteorImgHeight * scale) * Math.random() -
            meteorImgHeight * scale,
        });
        break;
      default:
        break;
    }
    // 对应属性合并到流行对象
    Object.assign(starBitmapImg, assignObjData);

    // 星星落下
    createjs.Tween.get(starBitmapImg)
      .wait(1000 * Math.random())
      .to(
        {
          x: randomValue ? height - assignObjData.y : assignObjData.x + height,
          y: height,
        },
        2000 * Math.random() + 5000
      );

    starImgList.push(starBitmapImg);
    // 插入舞台
    stage.addChild(starBitmapImg);
  }, []);

  // 检测流星是否超出边缘
  const judgeMeteorOverCanvas = useCallback((meteor) => {
    return (
      meteor.x <= -(meteorImgWidth * meteor.scaleX) + 0.1 ||
      meteor.y >= stage.canvas.height
    );
  }, []);

  // 检测流星是否超出边缘
  const judgeStarOverCanvas = useCallback((star) => {
    return star.x >= stage.canvas.width - 0.1 || star.y >= stage.canvas.height;
  }, []);

  // 清楚超出边缘的流星
  const clearMeteor = useCallback(
    (type = "meteorImg") => {
      let listArr, judgeMethod;
      switch (type) {
        case "meteorImg":
          listArr = meteorImgList;
          judgeMethod = judgeMeteorOverCanvas;
          break;
        case "star":
          listArr = starImgList;
          judgeMethod = judgeStarOverCanvas;
          break;
        default:
          break;
      }

      return new Promise((resolve) => {
        const length = listArr.length;
        for (let i = 0; i < length; i++) {
          if (listArr[i] && judgeMethod(listArr[i])) {
            stage.removeChild(listArr[i]);
            listArr.splice(i, 1);
            i--;
          }
        }
        resolve();
      });
    },
    [judgeMeteorOverCanvas, judgeStarOverCanvas]
  );

  useEffect(() => {
    // 初始化舞台,添加帧渲染时间
    initStage();
    // 创建多个闪烁星星
    resolveFunRepeat(createLightBall, 80);
    // 创建多个下坠流星
    resolveFunRepeat(createFallingMeteor, 40);
    // 创建可点击星星
    resolveFunRepeat(createClickableStar, 15);

    const interId = setInterval(() => {
      clearMeteor().then(() => {
        resolveFunRepeat(createInitXOrYFallingMeteor, 15);
      });
      clearMeteor("star").then(() => {
        console.log("🚀 starImgList", starImgList, starImgList.length);
        resolveFunRepeat(createClickableStar, 5);
      });
    }, 200 * Math.random() + 800);

    return () => clearInterval(interId);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    console.log(stage, "???");
  });
  return (
    <div className={style.canvasContainer} ref={canvasContainerRef}>
      <canvas id={style.canvas} ref={canvasRef} />
    </div>
  );
};

export default CanvasGame;
